package controlador;

import gui.PalcoPintura;

import java.util.ArrayList;
import java.util.List;

import javax.swing.ButtonGroup;
import javax.swing.JOptionPane;
import javax.swing.JToggleButton;

import modelo.diagrama.de.classes.Classe;
import modelo.diagrama.de.classes.Nota;
import modelo.diagrama.de.estados.EstadoFinal;
import modelo.diagrama.de.estados.EstadoInicial;
import modelo.diagramas.ElementoDeLigacao;
import modelo.diagramas.ElementoDeModelo;
import modelo.diagramas.ObjetoBase;
import modelo.estado.State;
import modelo.estado.StateAgregacaoSelecionado;
import modelo.estado.StateAssociacaoSelecionado;
import modelo.estado.StateComposicaoSelecionado;
import modelo.estado.StateElementoDeModeloSelecionado;
import modelo.estado.StateGeneralizacaoSelecionado;
import modelo.estado.StateNenhumSelecionado;

public class Controlador {

	private static int serialObjetos = 0;

	private static Controlador instance;

	public ElementoDeModelo origemSelecionado;

	public ElementoDeModelo destinoSelecionado;

	private List<ElementoDeModelo> elementosDeModeloAdicionados = new ArrayList<ElementoDeModelo>();

	public static final String DIAGRAMA_NENHUM = "NENHUM";

	public static final String DIAGRAMA_CLASSE = "CLASSE";

	public static final String DIAGRAMA_ESTADOS = "ESTADOS";

	public static final Integer LARGURA_MAXIMA_PALCO_PINTURA = 60000;

	public static final Integer ALTURA_MAXIMA_PALCO_PINTURA = 60000;

	private String diagramaSelecionado = DIAGRAMA_NENHUM;

	private ButtonGroup grupoDeBotoes = new ButtonGroup();

	private State estado = new StateNenhumSelecionado();

	private Controlador() {

	}

	public static Controlador getInstance() {
		if (instance == null) {
			instance = new Controlador();
		}
		return instance;
	}

	public static int getSerialObjetos() {
		return serialObjetos;
	}

	public static void setSerialObjetos(int serialObjetos) {
		Controlador.serialObjetos = serialObjetos;
	}

	public List<ElementoDeModelo> getElementosDeModeloAdicionados() {
		return elementosDeModeloAdicionados;
	}

	public void setElementosDeModeloAdicionados(
			List<ElementoDeModelo> elementosDeModelo) {
		this.elementosDeModeloAdicionados = elementosDeModelo;
	}

	public String getDiagramaSelecionado() {
		return diagramaSelecionado;
	}

	public void setDiagramaSelecionado(String diagramaSelecionado) {
		this.diagramaSelecionado = diagramaSelecionado;
	}

	public ElementoDeModelo getOrigemSelecionado() {
		return origemSelecionado;
	}

	public void setOrigemSelecionado(ElementoDeModelo origemSelecionado) {
		this.origemSelecionado = origemSelecionado;
	}

	public ElementoDeModelo getDestinoSelecionado() {
		return destinoSelecionado;
	}

	public void setDestinoSelecionado(ElementoDeModelo destinoSelecionado) {
		this.destinoSelecionado = destinoSelecionado;
	}

	public State getEstado() {
		return estado;
	}

	public void setEstado(State estado) {
		this.estado = estado;
	}

	public ButtonGroup getGrupoBotoes() {
		return grupoDeBotoes;
	}

	public void setGrupoBotoes(ButtonGroup groupBotoes) {
		this.grupoDeBotoes = groupBotoes;
	}

	// Adiciona os botoes no GroupButton para o controlador.
	public void adicionaBotoesNoGrupoDeBotoes(JToggleButton botao) {
		grupoDeBotoes.add(botao);
	}

	// Adiciona os elementos de modelo no palco
	public void adicionaElementoDeModelo(ElementoDeModelo elementoDeModelo) {
		elementoDeModelo.setSerialElementoDeModelo(serialObjetos);
		elementosDeModeloAdicionados.add(elementoDeModelo);
		setEstado(new StateNenhumSelecionado());
		grupoDeBotoes.clearSelection();
		serialObjetos++;
	}

	// Retorna um objetoSelecionado ou nao no X e Y informado
	public ElementoDeModelo verificaRetornaElementoDeModeloSelecionado(int x,
			int y) {
		for (int i = getElementosDeModeloAdicionados().size() - 1; i >= 0; i--) {
			if ((x < getElementosDeModeloAdicionados().get(i).getX()
					+ getElementosDeModeloAdicionados().get(i).getLargura())
					&& (x > getElementosDeModeloAdicionados().get(i).getX())) {
				if ((y < getElementosDeModeloAdicionados().get(i).getY()
						+ getElementosDeModeloAdicionados().get(i).getAltura())
						&& (y > getElementosDeModeloAdicionados().get(i).getY())) {
					this.setEstado(new StateElementoDeModeloSelecionado());
					this.getElementosDeModeloAdicionados().get(i)
							.setSelecionado(true);
					return getElementosDeModeloAdicionados().get(i);
				}
			}
		}
		return null;
	}

	// Retorna o objeto que esta com o status de selecionado.
	public ElementoDeModelo retornaElementoSelecionado() {
		for (int i = getElementosDeModeloAdicionados().size() - 1; i >= 0; i--) {
			if (getElementosDeModeloAdicionados().get(i).isSelecionado()) {
				return getElementosDeModeloAdicionados().get(i);
			}
		}
		return null;
	}

	// Limpa os objetos destino e origem selecionados.
	public void limpaOrigemDestinoSelecionado() {
		this.setOrigemSelecionado(null);
		this.setDestinoSelecionado(null);
	}

	// Remove ObjetoGrafico.
	public void removeObjetoGrafico(ElementoDeModelo oG) {
		getElementosDeModeloAdicionados().remove(oG);
	}

	// Metodo tira a selecao de todos os objetos.
	public void deSelecionarObjetos() {
		for (ElementoDeModelo oG : elementosDeModeloAdicionados) {
			oG.setSelecionado(false);
		}
	}

	// Metodo retorna o objetoSelecionado e seta para selecionado.
	public void testaSelecaoPinta(int x, int y) {

		// Inicialmente desSeleciona os objetos.
		deSelecionarObjetos();

		// Vasculha procurando pelo ElementoDeModeloSelecionado
		for (int i = getElementosDeModeloAdicionados().size() - 1; i >= 0; i--) {

			// No caso de elementodeligacao testar se foi selecionado.
			if (!(getElementosDeModeloAdicionados().get(i) instanceof Classe)
					&& !(getElementosDeModeloAdicionados().get(i) instanceof Nota)
					&& !(getElementosDeModeloAdicionados().get(i) instanceof EstadoInicial)
					&& !(getElementosDeModeloAdicionados().get(i) instanceof EstadoFinal)) {
				ElementoDeLigacao e = (ElementoDeLigacao) getElementosDeModeloAdicionados()
						.get(i);
				if (x >= e.getxPosicoes()[0] - 5
						&& x <= e.getxPosicoes()[1] + 5) {
					if (y >= e.getyPosicoes()[0] - 5
							&& y <= e.getyPosicoes()[1] + 5) {
						e.setSelecionado(true);
						System.out.println("Selecionou");
					}
				}
				if (x >= e.getxPosicoes()[1] - 5
						&& x <= e.getxPosicoes()[2] + 5) {
					if (y >= e.getyPosicoes()[1] - 5
							&& y <= e.getyPosicoes()[2] + 5) {
						e.setSelecionado(true);
						System.out.println("Selecionou");
					}
				}
			}

			// Se passar nos dois If ele esta clicando sobre um ElementoDeModelo
			if ((x < getElementosDeModeloAdicionados().get(i).getX()
					+ getElementosDeModeloAdicionados().get(i).getLargura())
					&& (x > getElementosDeModeloAdicionados().get(i).getX())) {
				if ((y < getElementosDeModeloAdicionados().get(i).getY()
						+ getElementosDeModeloAdicionados().get(i).getAltura())
						&& (y > getElementosDeModeloAdicionados().get(i).getY())) {

					if ((this.getEstado() instanceof StateComposicaoSelecionado)
							|| (this.getEstado() instanceof StateAgregacaoSelecionado)
							|| (this.getEstado() instanceof StateGeneralizacaoSelecionado)) {

						if (this.getOrigemSelecionado() == null) {

							if (this.getElementosDeModeloAdicionados().get(i) instanceof Nota) {
								this.limpaOrigemDestinoSelecionado();
								grupoDeBotoes.clearSelection();
								this.setEstado(new StateNenhumSelecionado());
								JOptionPane.showMessageDialog(PalcoPintura
										.getInstance(), "Objeto nao permitido");

							} else {
								this
										.setOrigemSelecionado(getElementosDeModeloAdicionados()
												.get(i));
								this.getElementosDeModeloAdicionados().get(i)
										.setSelecionado(true);
							}

						} else if (this.getDestinoSelecionado() == null) {

							if (this.getElementosDeModeloAdicionados().get(i) instanceof Nota) {
								this.limpaOrigemDestinoSelecionado();
								grupoDeBotoes.clearSelection();
								this.setEstado(new StateNenhumSelecionado());
								JOptionPane.showMessageDialog(PalcoPintura
										.getInstance(), "Objeto nao permitido");

							} else {
								this
										.setDestinoSelecionado(getElementosDeModeloAdicionados()
												.get(i));

							}

						} else if ((this.getOrigemSelecionado() != null)
								&& (this.getDestinoSelecionado() != null)) {
							this.limpaOrigemDestinoSelecionado();
							grupoDeBotoes.clearSelection();
							this.setEstado(new StateNenhumSelecionado());
						}
					} else if ((this.getEstado() instanceof StateAssociacaoSelecionado)) {

						if (this.getOrigemSelecionado() == null) {
							this
									.setOrigemSelecionado(getElementosDeModeloAdicionados()
											.get(i));
							this.getElementosDeModeloAdicionados().get(i)
									.setSelecionado(true);

						} else if (this.getDestinoSelecionado() == null) {
							this
									.setDestinoSelecionado(getElementosDeModeloAdicionados()
											.get(i));

						} else if ((this.getOrigemSelecionado() != null)
								&& (this.getDestinoSelecionado() != null)) {
							this.limpaOrigemDestinoSelecionado();
							grupoDeBotoes.clearSelection();
							this.setEstado(new StateNenhumSelecionado());
						}

					} else {

						// Limpa o grupo de botoes
						grupoDeBotoes.clearSelection();

						// Seta o Estado para ElementoDeModeloSelecionado
						setEstado(new StateElementoDeModeloSelecionado());

						// Seta o objeto selecionado para pintar a borda.
						getElementosDeModeloAdicionados().get(i)
								.setSelecionado(true);

					}
				}
			}
		}
	}

	// Responsavel por atualizar o x e y do elemento selecionado.
	public void atualizaPosicaoElementoSelecionado(int x, int y) {
		ElementoDeModelo objetoGrafico = retornaElementoSelecionado();

		if (objetoGrafico != null) {
			if (getEstado() instanceof StateElementoDeModeloSelecionado) {

				objetoGrafico.setX(x);
				objetoGrafico.setY(y);
			} else {
				Controlador.getInstance().deSelecionarObjetos();
				Controlador.getInstance().setEstado(
						new StateNenhumSelecionado());
			}
		}
	}

}
